package com.maikang.exammall.util;

import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import static com.maikang.exammall.entity.constant.ImageSizeConstant.QRCODE_LENGTH;


@Log4j2
@Component
@RequiredArgsConstructor
public class ImageUtil {
    private final CosUtil cosUtil;
    private static int recruitPosterWidth = 690;
    private static int recruitPosterHeight = 1156;
    private static int sharePkgBgWidth = 702;
    private static int sharePkgBgHeight = 997;
    private static int avatarWidth = 80;
    private static int avatarHeight = 80;
    private Font font;

    private Font getFont() {
        if (font != null) {
            return font;
        }
        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("static/font/ping_fang_regular.ttf");
            BufferedInputStream fb = new BufferedInputStream(inputStream);
            font = Font.createFont(Font.TRUETYPE_FONT, fb);
        } catch (FontFormatException | IOException e) {
            return null;
        }
        return font;
    }

    @SneakyThrows
    public String createQrCodeImage(String bgUrl, String avatarUrl, String username, String qrCodeUrl, String path) {

        // step1: resize bg
        BufferedImage bg = Thumbnails.of(new URL(bgUrl)).size(recruitPosterWidth, recruitPosterHeight).asBufferedImage();

        // step2: write text

//        String content = String.format("%s邀请您关注迈康体检\n长按识别二维码或保存图片", username);
//        String content = String.format("长按识别二维码或保存图片\n", username);
//        Font font = getFont();
//        Font font1 = font.deriveFont(Font.PLAIN, 26);
//        Color color1 = new Color(34, 34, 34);
//        Font font2 = font.deriveFont(Font.PLAIN, 24);
//        Color color2 = new Color(119, 119, 119);
//        bg = draw(bg, content, font1, color1, font2, color2, 385, null);

        // step3: overlie avatar image
//        if (StringUtils.hasLength(avatarUrl)) {
//            BufferedImage avatar = Thumbnails.of(new URL(avatarUrl)).size(avatarWidth, avatarHeight).asBufferedImage();
//            bg = drawImage(bg, avatar, 30, 1010);
//        }

        // step4: overlie qrcode image
        int curQRCodeWidth = 2 * QRCODE_LENGTH;
        int curQRCodeHeight = 2 * QRCODE_LENGTH;
        int bottomMargin = 66;
        if (StringUtils.hasLength(qrCodeUrl)) {
            BufferedImage qrcodeImg = Thumbnails.of(new URL(qrCodeUrl)).size(curQRCodeWidth, curQRCodeHeight).asBufferedImage();
            bg = drawImage(bg, qrcodeImg, (recruitPosterWidth-curQRCodeWidth)/2, recruitPosterHeight-curQRCodeHeight-bottomMargin);
        }

        return cosUtil.upload(path, bg);
    }


    @SneakyThrows
    public String createSharePackageImage(String pkgShareImgUrl, String hospitalName, String hospitalAddress, String pkgDetailUrl, String path) {
        // step0: create white outer background
        BufferedImage outerBg = new BufferedImage(sharePkgBgWidth, sharePkgBgHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = outerBg.createGraphics();
        graphics.setPaint(new Color(255, 255, 255));
        graphics.fillRect(0, 0, sharePkgBgWidth, sharePkgBgHeight);

        // step1: resize bg
        int idx = pkgShareImgUrl.lastIndexOf('/');
        String pre = pkgShareImgUrl.substring(0, idx + 1);
        String tail = pkgShareImgUrl.substring(idx + 1);
        String url = pre + URLEncoder.encode(tail, "utf-8");
        BufferedImage bg = Thumbnails.of(new URL(url)).size(sharePkgBgWidth, sharePkgBgHeight).asBufferedImage();
        bg = drawImage(outerBg, bg, 0, 0);

        // step2: writeText
        Font contentFont = getFont().deriveFont(Font.PLAIN, 20);
        Color contentColor = new Color(102, 102, 102);
        String content = String.format("体检机构：%s\n机构地址：%s", hospitalName, hospitalAddress);
        bg = draw(bg, content,
                contentFont, contentColor, 32, 882, // 852
                contentFont, contentColor, 32, 927,
                485, null);

        // step3: get pkgDetail Qrcode pic
        BufferedImage pkgDetailQrCode = QRCodeUtil.createImageWithDefaultLogo(pkgDetailUrl);

        // step4: overlap pkgDetail
        bg = drawImage(bg, pkgDetailQrCode, 545, 832);
        return cosUtil.upload(path, bg);

    }

    @SneakyThrows
    private BufferedImage drawImage(BufferedImage bgImg, BufferedImage toAddImg, int x, int y) {
        Objects.requireNonNull(bgImg, ">>>>>背景图不可为空");
        Objects.requireNonNull(toAddImg, ">>>>>待叠加图不可为空");
        if ((toAddImg.getWidth() + x) > bgImg.getWidth() || (toAddImg.getHeight() + y) > bgImg.getHeight()) {
            throw new IOException(">>>>>二维码宽度+x不可以超过背景图的宽度,长度同理");
        }
        Graphics2D g = bgImg.createGraphics();
        g.drawImage(toAddImg, x, y, toAddImg.getWidth(), toAddImg.getHeight(), null);
        return bgImg;
    }


    // belows are static pure util method

    /**
     * @param source  底图
     * @param content 内容（\n隔开的内容）
     * @param color1  标题颜色
     * @param alpha   模糊程度0.1-1.0f
     * @return
     */
    public static BufferedImage textMark(Image source,
                                         String content,
                                         Font font1,
                                         Color color1,
                                         int x1, // 32
                                         int y1, // 852

                                         Font font2,
                                         Color color2,
                                         int x2,  // 32
                                         int y2,  // 897
                                         int rowWidth, // 485
                                         float alpha, String tempFilePath) {

        List<String> contents = Arrays.asList(content.split("\n"));
        try {
            Font Dfont = (font1 == null) ? new Font("宋体", 20, 13) : font1;
            //最关键的代码来了：

            BufferedImage image = new BufferedImage(source.getWidth(null), source.getHeight(null), BufferedImage.TYPE_INT_RGB);
            Graphics2D g = image.createGraphics();
            g.drawImage(source, 0, 0, null);

            g.setColor(color1);
            g.setFont(Dfont);
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));

            drawStringWithFontStyleLineFeed(g, contents.get(0), x1, y1, rowWidth);

            g.setColor(color2);
            g.setFont(font2);
            drawStringWithFontStyleLineFeed(g, contents.get(1), x2, y2, rowWidth);

            g.dispose();
            if (tempFilePath != null) {
                File outputfile = new File(tempFilePath);
                ImageIO.write(image, "jpg", outputfile);
            }
            return image;
        } catch (Exception e) {
            log.error("failed to textMark", e);
        }
        return null;
    }

    // for recruit poster
    public static BufferedImage textMark(Image source,
                                         String content,
                                         Font font1,
                                         Color color1,
                                         Font font2,
                                         Color color2,
                                         int rowWidth,
                                         float alpha, String tempFilePath) {

        int x1 = 126;
        int y1 = 1031;
        int x2 = 126;
        int y2 = 1084;
        List<String> contents = Arrays.asList(content.split("\n"));
        try {
            Font Dfont = (font1 == null) ? new Font("宋体", 20, 13) : font1;
            BufferedImage image = new BufferedImage(source.getWidth(null), source.getHeight(null), BufferedImage.TYPE_INT_RGB);
            Graphics2D g = image.createGraphics();
            g.drawImage(source, 0, 0, null);

            g.setColor(color1);
            g.setFont(Dfont);
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));

            drawStringWithFontStyleLineFeed(g, contents.get(0), x1, y1, rowWidth);
//
//            int strWidth = getStringLength(g, contents.get(0));
//            if (strWidth > rowWidth) {
//                y2 = 1113;
//            }
//            g.setColor(color2);
//            g.setFont(font2);
//            drawStringWithFontStyleLineFeed(g, contents.get(1), x2, y2, rowWidth);

            g.dispose();
            if (tempFilePath != null) {
                File outputfile = new File(tempFilePath);
                ImageIO.write(image, "jpg", outputfile);
            }
            return image;
        } catch (IOException e) {
            log.error("failed to textMark", e);
        }

        return null;
    }


    /**
     * 手账4模板生成
     *  @param source       底图
     * @param content      内容
     * @param tempFilePath 临时存放插入文字的图片地址
     * @return
     */
    public static BufferedImage draw(Image source,
                                     String content,
                                     Font font1,
                                     Color color1,
                                     int x1, // 32
                                     int y1, // 852

                                     Font font2,
                                     Color color2,
                                     int x2,  // 32
                                     int y2,  // 897
                                     int rowWidth, // 485
                                     String tempFilePath) {
        return textMark(source, content, font1, color1, x1, y1, font2, color2, x2, y2, rowWidth, 1.0f, tempFilePath);
    }

    public static BufferedImage draw(Image source,
                                     String content,
                                     Font font1,
                                     Color color1,
                                     Font font2,
                                     Color color2,
                                     int rowWidth,
                                     String tempFilePath) {
        return textMark(source,
                content,
                font1,
                color1,
                font2,
                color2,
                rowWidth,
                1.0f, tempFilePath);
    }


    /**
     * 获取字符长度
     *
     * @param g
     * @param str
     * @return
     */
    private static int getStringLength(Graphics g, String str) {
        char[] strcha = str.toCharArray();
        int strWidth = g.getFontMetrics().charsWidth(strcha, 0, str.length());
        System.out.println("字符总宽度:" + strWidth);
        return strWidth;
    }

    /**
     * 每行的字符数
     *
     * @param strnum   字符数
     * @param rowWidth 行宽度
     * @param strWidth 字符宽度
     * @return
     */
    private static int getRowStrNum(int strnum, int rowWidth, int strWidth) {
        int rowstrnum = 0;
        rowstrnum = (rowWidth * strnum) / strWidth;
        System.out.println("每行的字符数:" + rowstrnum);
        return rowstrnum;
    }

    /**
     * 获得行数
     *
     * @param strWidth 字符总宽度
     * @param rowWidth 行宽度
     * @return
     */
    private static int getRows(int strWidth, int rowWidth) {
        int rows = 0;
        if (strWidth % rowWidth > 0) {
            rows = strWidth / rowWidth + 1;
        } else {
            rows = strWidth / rowWidth;
        }
        System.out.println("行数:" + rows);
        return rows;
    }


    /**
     * 获得每行字符高度
     *
     * @param g
     * @return
     */
    private static int getStringHeight(Graphics g) {
        int height = g.getFontMetrics().getHeight() + 5;
        System.out.println("字符高度:" + height);
        return height;
    }

    /**
     * @param g          Graphics（包含设置好字体）
     * @param strContent 文本内容
     * @param loc_X      坐标
     * @param loc_Y
     * @param rowWidth   每行宽度
     */
    private static void drawStringWithFontStyleLineFeed(Graphics g, String strContent, int loc_X, int loc_Y, int rowWidth) {
        //获取字符串 字符的总宽度
        int strWidth = getStringLength(g, strContent);
        System.out.println("每行字符宽度:" + rowWidth);
        //获取字符高度
        int strHeight = getStringHeight(g);
        //字符串总个数
        System.out.println("字符串总个数:" + strContent.length());
        if (strWidth > rowWidth) {
            int rowstrnum = getRowStrNum(strContent.length(), rowWidth, strWidth);
            int rows = getRows(strWidth, rowWidth);
            String temp = "";
            for (int i = 0; i < rows; i++) {
                //获取各行的String
                if (i == rows - 1) {
                    //最后一行
                    temp = strContent.substring(i * rowstrnum, strContent.length());
                } else {
                    temp = strContent.substring(i * rowstrnum, i * rowstrnum + rowstrnum);
                }
                if (i > 0) {
                    //第一行不需要增加字符高度，以后的每一行在换行的时候都需要增加字符高度
                    loc_Y = loc_Y + strHeight;
                    loc_X = loc_X + strWidth * 5;  // 空格对齐
                }
                g.drawString(temp, loc_X, loc_Y);
            }
        } else {
            //直接绘制
            g.drawString(strContent, loc_X, loc_Y);
        }
    }
}
